package org.zjvis.datascience.service.gis;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zjvis.datascience.common.dto.gis.GisTabsDTO;
import org.zjvis.datascience.common.gis.GisUtils.GisUtil;
import org.zjvis.datascience.common.util.JwtUtil;
import org.zjvis.datascience.common.util.StringUtil;
import org.zjvis.datascience.common.vo.gis.GisTabsVO;
import org.zjvis.datascience.service.TaskService;
import org.zjvis.datascience.service.dataset.DatasetService;
import org.zjvis.datascience.service.mapper.GisTabsMapper;

import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static org.zjvis.datascience.common.gis.GisUtils.GisUtil.getTabDataJson;

@Service
public class GisTabsService {
    private final static Logger logger = LoggerFactory.getLogger(GisTabsService.class);

    @Autowired
    private GisTabsMapper gisTabsMapper;

    public List<GisTabsDTO> queryTabsByProjectId(Long pid) {
        return gisTabsMapper.queryTabsByProjectId(pid);
    }

    public List<String> queryTabNamesByProjectId(Long pid) {
        return gisTabsMapper.queryTabNamesByProjectId(pid);
    }


    public void updateTabJson(GisTabsVO gisTabsVO, GisTabsDTO tabDTO) {
        if (tabDTO.getDataJson() == null) {
            JSONObject defaultDataJson = getTabDataJson();
            tabDTO.setDataJson(defaultDataJson.toJSONString());
        }
        if (gisTabsVO.getTabName() != null) {
            tabDTO.setTabName(gisTabsVO.getTabName());
        }
        if (gisTabsVO.getData() != null) {
            JSONObject oldJson = tabDTO.tab().getData();
            JSONObject newJson = gisTabsVO.getData();
            recursion(oldJson, newJson);
            tabDTO.setDataJson(oldJson.toJSONString());
        }
    }

    /**
     * 模仿taskService中跟新dataJson的方法
     *
     * @param oldObj
     * @param currentObj
     */
    public void recursion(Object oldObj, Object currentObj) {
        if (oldObj instanceof JSONArray && currentObj instanceof JSONArray) {
            JSONArray oldJsonArray = (JSONArray) oldObj;
            JSONArray currentJsonArray = (JSONArray) currentObj;
            int length1 = oldJsonArray.size();
            int length2 = currentJsonArray.size();
            int i = 0;
            int j = 0;
            while (i < length1 && j < length2) {
                if (!(oldJsonArray.get(i) instanceof JSONArray || oldJsonArray
                        .get(i) instanceof JSONObject)) {
                    oldJsonArray.set(i, currentJsonArray.get(j));
                } else {
                    recursion(oldJsonArray.get(i), currentJsonArray.get(j));
                }
                ++i;
                ++j;
            }
            int m = i;
            while (i < length1) {
                oldJsonArray.remove(m);
                ++i;
            }
            while (j < length2) {
                oldJsonArray.add(currentJsonArray.get(j));
                ++j;
            }
        } else if (oldObj instanceof JSONObject && currentObj instanceof JSONObject) {
            JSONObject jsonObject = (JSONObject) currentObj;
            JSONObject oldJsonObject = (JSONObject) oldObj;
            Set<String> keySet = jsonObject.keySet();
            Iterator<String> iterator = keySet.iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                if (!oldJsonObject.containsKey(key)) {
                    oldJsonObject.put(key, jsonObject.get(key));
                } else {
                    if (oldJsonObject.get(key) instanceof JSONObject && jsonObject
                            .get(key) instanceof JSONObject) {
                        recursion(oldJsonObject.get(key), jsonObject.get(key));
                    } else if (oldJsonObject.get(key) instanceof JSONArray && jsonObject
                            .get(key) instanceof JSONArray) {
                        recursion(oldJsonObject.get(key), jsonObject.get(key));
                    } else {
                        oldJsonObject.put(key, jsonObject.get(key));
                    }
                }
            }
        }
    }

    public Long saveTab(GisTabsDTO tab) {
        gisTabsMapper.save(tab);
        return tab.getId();
    }


    public void deleteTabByIds(Long tabId) {
        gisTabsMapper.deleteTabByIds(tabId);
    }


    public GisTabsDTO queryTabInfoById(Long tabId) {
        return gisTabsMapper.queryTabInfoById(tabId);
    }

    public boolean update(GisTabsDTO tab) {
        return gisTabsMapper.update(tab);
    }

    /**
     * 添加画布
     *
     * @param projectId
     * @param name
     * @return GisTabsDTO
     */
    public GisTabsDTO addTabs(Long projectId, String name) {
        List<String> names = queryTabNamesByProjectId(projectId);
        JSONObject dataJson = getTabDataJson();
        String setName = name == null ? GisUtil.TABS_DEFAULT_NAME : name;
        String newName = StringUtil.genAutoIncreaseName(names, setName);
        GisTabsDTO emptyTabsDTO = new GisTabsDTO();
        emptyTabsDTO.setUserId(JwtUtil.getCurrentUserId());
        emptyTabsDTO.setProjectId(projectId);
        emptyTabsDTO.setDataJson(dataJson.toJSONString());
        emptyTabsDTO.setPipelineId(null);
        emptyTabsDTO.setTaskId(null);
        emptyTabsDTO.setTabName(newName);
        saveTab(emptyTabsDTO);
        return emptyTabsDTO;
    }

    public GisTabsDTO addTabsByProjectId(Long projectId) {
        return addTabs(projectId, null);
    }


    /**
     * 复制画布并改名
     *
     * @param tabId
     * @return
     */
    public GisTabsDTO copyTab(Long tabId, Long projectId, boolean bKgTab) {
        GisTabsDTO oldTab;
        if (bKgTab) {
            oldTab = gisTabsMapper.queryGisTabInfoById(tabId);
        } else {
             oldTab = gisTabsMapper.queryTabInfoById(tabId);
        }
        oldTab.setId(null);
        String checkedName = StringUtil.genAutoIncreaseName(queryTabNamesByProjectId(projectId), oldTab.getTabName());
        oldTab.setTabName(checkedName);
        gisTabsMapper.save(oldTab);
        return oldTab;
    }

    public Long getMaxId(Long userId) {
        return gisTabsMapper.getMaxId(userId);
    }

}

